package config

import (
	"bytes"
	"encoding/json"
	"flag"
	"github.com/fsnotify/fsnotify"
	"github.com/pkg/errors"
	"github.com/spf13/viper"
	"io/ioutil"
	"os"
)

var filePath string

func init() {
	flag.StringVar(&filePath, "f", "./config.json", `config file path, default to "./config.json"`)
}

// LoadConfig loads a json config file located by commandline flag '-config'
func LoadConfig(v interface{}) error {
	buf, e := ioutil.ReadFile(filePath)
	if e != nil {
		return errors.Wrap(e, "read config file failed, did you set the right path?")
	}
	if e := json.Unmarshal(buf, v); e != nil {
		return errors.Wrap(e, "unmarshal config file failed, please check the file path and content")
	}
	return nil
}

func LoadConfigWithPath(v interface{}, cfgPath string) error {
	buf, e := ioutil.ReadFile(cfgPath)
	if e != nil {
		return errors.Wrap(e, "read config file failed, did you set the right path?")
	}
	if e := json.Unmarshal(buf, v); e != nil {
		return errors.Wrap(e, "unmarshal config file failed, please check the file path and content")
	}
	return nil
}

type local struct {
	client     *os.File
	wait       *uint64
	path       string
	configType string
}

func NewLocal(conf *Config) (IConfigService, error) {
	client, err := os.Open(conf.Path)
	if err != nil {
		return nil, err
	}
	return &local{client: client, path: conf.Path, configType: conf.Type}, nil
}

func (c *local) Init() *viper.Viper {
	v := viper.New()
	v.SetConfigType(c.configType)
	if err := c.GetViper(v); err != nil {
		panic("local config get err:" + err.Error())
	}
	go c.Watch(v)
	return v
}

// GetViper 从中间件中获取配置
func (c *local) GetViper(v *viper.Viper) error {
	data, err := c.Get()
	if err != nil {
		return errors.New("get local config fail:" + err.Error())
	}
	if err = v.ReadConfig(bytes.NewBuffer(data)); err != nil {
		return err
	}
	return nil
}

func (c *local) Get() ([]byte, error) {
	c.client.Seek(0, 0) //重置到最开始
	return ioutil.ReadAll(c.client)
}

func (c *local) Set(value string) error {
	file, err := os.OpenFile(c.path, os.O_RDWR|os.O_CREATE, 0755)
	if err != nil {
		return err
	}
	_, err = file.Write([]byte(value))
	return err
}

func (c *local) Watch(v *viper.Viper) {
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		panic(err)
	}

	if err = watcher.Add(c.path); err != nil {
		panic(err)
	}

	defer watcher.Close()

	for {
		select {
		case event, ok := <-watcher.Events: // 正常的事件的处理逻辑
			if !ok {
				continue
			}
			if event.Op&fsnotify.Write == fsnotify.Write {
				if err = c.GetViper(v); err != nil && CallBack != nil {
					CallBack(v)
				}
			}
		case _, ok := <-watcher.Errors:
			if !ok {
				break
			}
		}
	}
}

func (c *local) SetPath(key string) {
	c.path += key
}
